/**
 * Created by liu on 2019/10/23.
 * 主要分几个部分
 * 第一部分 基础通用功能
 * 第二部分 总结历来项目中用到的时间处理
 * 第三部分 string array等对象的 原型方法扩展 也很常用
 */
import Vue from 'vue'
+
(function() {
    "use strict";
    /**
     * 基础部分
     */
    var part1 = {
        halfChar: '<i style="visibility: hidden">..</i>', //半个字符
        twoChar: '<i style="visibility: hidden">呵呵</i>', //2个字符
        url: /^http[s]?:\/\/.*/, //URL地址
        tel: /^1[0-9]{10}$/,
        ranStr: "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678",
        email: /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/,
        randomNum: "", //获取的随机数
        posInt: /^[0-9]+$/,
        discount: /(^0\.\d+$)|(^[01]$)/, //记一下 可鞥会常用 折扣 0-1的
    }

    //为空判断 0
    part1.empty = function(cont) {
        if (cont === 0) return false;
        return (cont == 'null' || cont == null || typeof(cont) == "undefined" || cont == "undefined" || cont == "") ? true : false;
    }
    part1.isTel = function(str) {
        return this.tel.test(str)
    }
    part1.isPosInt = function(str) {
        return this.posInt.test(str)
    }

    part1.toStr = function(o) {
        return o ? o.toString() : ''
    }

    part1.ConstDocStatusList = [
        { code: 'L', label: '维护' },
        { code: 'S', label: '审核' },
        { code: 'E', label: '二审' },
        { code: 'Q', label: '结清' },
        { code: 'T', label: '提交' }
    ]
    part1.ConstDocStatusList.getLabel = (code) => {
        const item = part1.ConstDocStatusList.find(o => o.code === code)
        return item ? item.label : ''
    }


    //对于电商项目的价格 设置保留n个小数<如果只传一个参数就默认的保留2位小数> toFixed 把数字转换为字符串
    part1.setTwoNum = function(price, n) {
        // if(price<0){ price = 0 };
        return isNaN(price) ? 0 : (part1.empty(n) ? new Number(price).toFixed(2) : new Number(price).toFixed(n));
    };

    part1.toNumber = function(inObj, p) {
        try {
            let d = parseFloat(inObj)
            return isNaN(d) ? 0 : (p ? d.toFixed(Math.abs(p)) : d)
        } catch (e) {
            console.error('error: wfy.toNumber')
            console.error(e)
            return 0
        }
    }

    // 数字 --> 单价，默认2位小数
    part1.toPrice = function(price, n = 2) {
        return this.setTwoNum(price, n)
    }

    // 数字 --> 金额，默认2位小数，千分位显示
    part1.toAmount = function(amount, n = 2) {
        return this.toThousands(this.setTwoNum(amount, n))
    }

    //小数转百分比 并默认保留2位小数
    part1.toPercent = function(price, n) {
        var str = this.setTwoNum(Number(price * 100), n);
        str += "%";
        return str;
    }

    //百分比转小数
    part1.toPoint = function(price, n) {
        price = (price || '').toString();
        return this.setTwoNum(Number(price.replace('%', '') / 100), n);
    }

    //金额 转 千位符
    part1.toThousands = function(num) {
        num = num + '';
        var source = num.replace(/\,|\￥/g, "").split(".");
        source[0] = source[0].replace(new RegExp('(\\d)(?=(\\d{3})+$)', 'ig'), "$1,");
        return source.join(".");
    }

    // 返回字符串的实际长度, 一个汉字算2个长度
    part1.strlen = function(str) {
        var str = str || '';
        return str.replace(/[^\x00-\xff]/g, "**").length;
    }

    //字符串超出省略   len 取双倍！比如要截取三个字 那么设置len参数为6  默认长度设置10吧
    part1.cutstr = function(str, len) {
        len = len || 10;
        var restr = str;
        var wlength = str.replace(/[^\x00-\xff]/g, "**").length;
        if (wlength > len) {
            for (var k = len / 2; k < str.length; k++) {
                if (str.substr(0, k).replace(/[^\x00-\xff]/g, "**").length >= len) {
                    restr = str.substr(0, k) + "...";
                    break;
                }
            }
        }
        return restr;
    }

    //列表名称 要求对齐，不够四个字的中间空格 填充---------以及2个字三个字的姓名----------
    part1.visibility = function(str) {
        var strlen = str.length;
        if (strlen == 4) {
            return str;
        }
        if (strlen == 3) {
            var strarr = str.split("");
            return strarr[0] + part1.halfChar + strarr[1] + part1.halfChar + strarr[2];
        }
        if (strlen == 2) {
            var strarr = str.split("");
            return strarr[0] + part1.totaChar + strarr[1];
        }
        if (strlen == 1) {
            return str;
        }
    }

    //名字 对齐（暂时不考虑四个字以上的名字）
    part1.visiname = function(str) {
        var strlen = str.length;
        switch (strlen) {
            case 2:
                var strarr = str.split("");
                return strarr[0] + part1.halfChar + part1.halfChar + strarr[1];
                break;
            default:
                return str;
                break;
        }
    }

    /**
     * 数组根据数组对象中的某个属性值进行排序的方法
     * 使用例子：newArray.sort(wfy.sortBy('number',false)) //表示根据number属性降序排列;若第二个参数不传递，默认表示升序排序
     * var resarr = re.sort(wfy.sortBy('kcssje',false));//从大大小排列
     * @param attr 排序的属性 如number属性
     * @param rev true表示升序排列，false降序排序
     * */
    part1.sortBy = function(attr, rev) {
            //第二个参数没有传递 默认升序排列
            if (rev == undefined) {
                rev = 1;
            } else {
                rev = (rev) ? 1 : -1;
            }
            return function(a, b) {
                a = a[attr];
                b = b[attr];
                if (a < b) {
                    return rev * -1;
                }
                if (a > b) {
                    return rev * 1;
                }
                return 0;
            }
        }
        /**
         * 对象数组根据时间排序
         * @param {*} obj  要排序的对象数组
         * @param {*} attr 时间的key值（那个属性）
         * @param {*} rev 默认或1 升序 -1降序
         * return 当前对象数组
         */
    part1.sortDate = function(obj, attr, rev) {
        return obj.sort(function(a, b) {
            return (new Date(a[attr]).getTime() - new Date(b[attr]).getTime()) * (rev ? rev : 1)
        });
    }

    /*
     * 汉子中文排序
     * 参数：arr 排序的数组; key 数组内的需要比较的元素属性
     * 使用例子：
     * 1. var arrs = ['南京', '北京', '上海', '杭州', '深圳']; 单纯的数组。key值不需要传
     * 2. [{name: '北京', code: '01', info: {province: '北京'}},
     * 比较的是name，传入的就是 'name'
     * 比较的是数组元素属性info内的province属性，传入的就是 'info.province'
     * eg wfy.sortChinese(shopinfo,'clientName');
     * console.log(shopinfo)--------直接修改原来的数据
     * */
    part1.sortChinese = function(arr, key) {
            /* 获取数组元素内需要比较的值 */
            var getValue = function(option) { // 参数： option 数组元素
                if (!key) return option
                var data = option
                key.split('.').filter(function(item) {
                    data = data[item]
                })
                return data + ''
            }
            arr.sort(function(item1, item2) {
                return getValue(item1).localeCompare(getValue(item2), 'zh-CN');
            })
        }
        /**
         * 单据类详情 数据的删除和增加操作，已经存在的不添加（即 对象数组中 删除或增加对象）
         * 参数
         *  row 要变化的list  对象数组
         *  initData 原始的list 对象数组
         *  key  list中唯一值的 key
         *  type 操作类型 add 和 del
         * 示例
         * var addarr = [
                {priceCode: "20200601", itemCode: "AK17302137C139", itemName: "女童亲肤棉宝长裤", itemStyle: "AK3021",},
                {priceCode: "2020010851", itemCode: "AK17302137C188", itemName: "女童亲肤棉宝长裤", itemStyle: "AK3021",}
            ]
            var dearr = [
                {priceCode: "20200601", itemCode: "AM1468140A75", itemName: "女童亲肤棉宝长裤", itemStyle: "AK3021",},
            ]
            this.tableData = this.concatRow(addarr,this.tableData,'itemCode','add');
            setTimeout(()=>{
                this.tableData = this.concatRow(dearr,this.tableData,'itemCode','del');
            },1000)
            注意：row 多条数据的时候 采用遍历row 逐条加入的方式
         */
    part1.operObjectInArr = function(row, initData, key, type) {
        if (type == 'add') {
            var flag = true;
            if (!row) {
                return false;
            } else {
                row.map((item) => {
                    var values = item[key];
                    for (const i in initData) {
                        if (initData[i][key] == values) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        initData.push(item);
                    }
                })
            }
        }
        if (type == 'del') {
            //循环一条一条的删
            var index = -1;
            if (!row) {
                return false;
            } else {
                row.map((item) => {
                    var values = item[key]; //要删除对象的 某个唯一值
                    for (const i in initData) {
                        if (initData[i][key] == values) {
                            index = i;
                            break;
                        }
                    }
                    if (index != -1) {
                        initData.splice(index, 1);
                    }
                })
            }
        }
        return initData;
    }

    /**
     * operObjectInArr 升级版
     * 区别：已经存在的 可以根据参数 设置 不添加 还是 覆盖
     * @param {*} fromArr 要操作的数据 对象数组
     * @param {*} toArr 被添加的数据  对象数组
     * @param {*} key fromArr的list中唯一值的 key
     * @param {*} operType 操作类型 add 和 del
     * @param {*} listType 布尔 true 为覆盖
     */
    part1.operObjectInArrs = function(fromArr, toArr, key, operType, listType = false) {
        if (operType == 'add') {
            if (!fromArr) {
                return false;
            } else {
                fromArr.forEach((item, index) => {
                    var flag = false;
                    toArr.forEach((list, sum) => {
                        if (list[key] == item[key]) {
                            flag = true; //存在  就是true
                            if (listType) {
                                toArr[sum] = item;
                            }
                        }
                    })
                    if (!flag) {
                        toArr.push(item);
                    }
                });
            }
        }
        if (operType == 'del') {
            //循环一条一条的删
            var index = -1;
            if (!fromArr) {
                return false;
            } else {
                fromArr.map((item) => {
                    var values = item[key]; //要删除对象的 某个唯一值
                    for (const i in toArr) {
                        if (toArr[i][key] == values) {
                            index = i;
                            break;
                        }
                    }
                    if (index != -1) {
                        toArr.splice(index, 1);
                    }
                })
            }
        }
        return toArr;
    }
    /**
     * 2021/5/24 operObjectInArrs 再升级 --- key值存在多个的情况
     * @param {*} operArr 要操作的数据 对象数组
     * @param {*} updateArr 被添加的数据  对象数组
     * @param {*} key 对象中的key，一个key的时候可以使用字符串格式！，多个用数组
     * @param {*} operType 操作类型 add 和 del
     * @param {*} listType 布尔 true 为覆盖
     */
    part1.operObjectArray = function(operArr,updateArr,key,operType, listType = false){
        //operArr updateArr 数据准确性不做判断
        let keys = this.isArray(key) ? key : [key];
        //添加
        if(operType =='add'){
            operArr.some((item)=>{
                let keyFlag = false;
                if(updateArr.length == 0){
                    updateArr.push(item)
                }else{
                    updateArr.forEach((element,index) => {
                        //没想出来 如何动态的实现不定key个数的 并且判断，先暂时挨个情况判断
                        if(keys.length == 1 ){
                            if(element[keys[0]] != item[keys[0]]){
                                keyFlag = true;
                            }
                        }
                        if(keys.length == 2){
                            if((element[keys[0]] == item[keys[0]]) && (element[keys[1]] == item[keys[1]])){
                                keyFlag = true;
                            }
                        }                           
                        listType && (updateArr[index] = item);

                    });
                    !keyFlag && updateArr.push(item);
                }
            })
        }
        if(operType=='del'){
            //循环一条一条的删
            let idx = -1;
            operArr.some((item)=>{
                if(updateArr.length == 0){
                    return updateArr;
                }else{
                    updateArr.forEach((element,index) => {
                        if(keys.length == 1){
                            if(element[keys[0]] == item[keys[0]]){
                                idx = index;
                            }
                        }
                        if(keys.length == 2){
                            if((element[keys[0]] == item[keys[0]]) && (element[keys[1]] == item[keys[1]])){
                                idx = index;
                            }
                        }
                    });
                    if (idx != -1) {
                        updateArr.splice(idx, 1);
                    }
                }
            })
        }
        return updateArr;
    }

    //四舍五入取整数（保存几位）Math.round(price)
    //获取随机数（中英文都有的）
    /*getRnd  默认两个参数，第一个参数传数字，表示位数。
     *        第二个参数可不写，是布尔型，true和false都行。加上这个参数表示纯数字的随机数
     */
    part1.getRnd = function(n, blean) {
        part1.randomNum = '';
        if (blean == "" || blean == true || blean == false) {
            for (var i = 0; i < n; i++) {
                part1.randomNum += Math.floor(Math.random() * 10);
            }
        } else {
            for (var i = 0; i < n; i++) {
                var j = parseInt(part1.ranStr.length * Math.random());
                part1.randomNum += part1.ranStr.charAt(j);
            }
        }
        return part1.randomNum;
    };
	part1.getScore = function(score){
		let result = "";
		// A 优秀 <0.85
		// B 良好 [0.85,0.95)
		// C 正常 [0.95,1.05)
		// D 轻危 [1.05,1.15)
		// E 危险 [1.15,1.25)
		// F 恶劣 >=1.25
		if(score < 0.8){
			result = "A(优秀)";
		}else if(score >= 0.85 && score < 0.95){
			result = "B(良好)";
		}else if(score >= 0.95 && score < 1.05){
			result = "C(正常)";
		}else if(score >= 1.05 && score < 1.15){
			result = "D(轻微)";
		}else if(score >= 1.15 && score < 1.25){
			result = "E(危险)";
		}else{
			result = "F(恶劣)";
		}
		return result;
	},
	part1.getScoreLever = function(score){
		let result = "";
		// A 优秀 <0.85
		// B 良好 [0.85,0.95)
		// C 正常 [0.95,1.05)
		// D 轻危 [1.05,1.15)
		// E 危险 [1.15,1.25)
		// F 恶劣 >=1.25
		if(score < 60){
			result = "E";
		}else if(score >= 60 && score < 70){
			result = "D";
		}else if(score >= 70 && score < 80){
			result = "C";
		}else if(score >= 80 && score < 90){
			result = "B";
		}else if(score >= 90 && score <= 100){
			result = "A";
		}
		return result;
	},
    part1.getRandom = function(len) {
        //默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
        var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
        var tempLen = chars.length,
            tempStr = '';
        for (var i = 0; i < len; ++i) {
            tempStr += chars.charAt(Math.floor(Math.random() * tempLen));
        }
        return tempStr;
    };
    //精确 加法
    part1.accAdd = function(arg1, arg2) {
        var r1, r2, m, c;
        try {
            r1 = arg1.toString().split(".")[1].length;
        } catch (e) {
            r1 = 0;
        }
        try {
            r2 = arg2.toString().split(".")[1].length;
        } catch (e) {
            r2 = 0;
        }
        c = Math.abs(r1 - r2);
        m = Math.pow(10, Math.max(r1, r2));
        if (c > 0) {
            var cm = Math.pow(10, c);
            if (r1 > r2) {
                arg1 = Number(arg1.toString().replace(".", ""));
                arg2 = Number(arg2.toString().replace(".", "")) * cm;
            } else {
                arg1 = Number(arg1.toString().replace(".", "")) * cm;
                arg2 = Number(arg2.toString().replace(".", ""));
            }
        } else {
            arg1 = Number(arg1.toString().replace(".", ""));
            arg2 = Number(arg2.toString().replace(".", ""));
        }
        return (arg1 + arg2) / m;
    }

    //精确 减法
    part1.accSub = function(arg1, arg2) {
        var r1 = 0,
            r2 = 0,
            r3 = 0;
        try {
            r1 = (arg1 + '').split('.')[1].length;
        } catch (err) {
            r1 = 0;
        }
        try {
            r2 = (arg2 + '').split('.')[1].length;
        } catch (err) {
            r2 = 0;
        }
        r3 = Math.pow(10, Math.max(r1, r2));
        return (part1.accMul(arg1, r3) - part1.accMul(arg2, r3)) / r3;
    }

    //精确 乘法
    part1.accMul = function(arg1, arg2) {
        var m = 0,
            s1 = arg1.toString(),
            s2 = arg2.toString();
        try {
            m += s1.split(".")[1].length;
        } catch (e) {}
        try {
            m += s2.split(".")[1].length;
        } catch (e) {}
        return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
    }

    //精确 除法
    part1.accDiv = function(arg1, arg2) {
        var r1 = arg1 + '',
            r2 = arg2 + '',
            r3 = 0,
            r4 = 0;
        try {
            r3 = r1.split('.')[1].length;
        } catch (err) {
            r3 = 0;
        }
        try {
            r4 = r2.split('.')[1].length;
        } catch (err) {
            r4 = 0;
        }
        return part1.accMul((Number(r1.replace('.', '')) / Number(r2.replace('.', ''))), Math.pow(10, r4 - r3));
    };

    /*
     * uuid
     * 可以指定长度和基数
     * uuid(8, 2) // "01001010"  (base=2)
     * uuid(8, 10) // "47473046" (base=10)
     * uuid(8, 16) // "098F4D35" (base=16)
     * */
    part1.uuid = function(len, radix) {
            var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
            var uuid = [],
                i;
            radix = radix || chars.length;
            if (len) {
                for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
            } else {
                var r;
                uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
                uuid[14] = '4';
                for (i = 0; i < 36; i++) {
                    if (!uuid[i]) {
                        r = 0 | Math.random() * 16;
                        uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
                    }
                }
            }
            return uuid.join('');
        }
        //长度为32位，没有规律，由数字和小写字母组成 zff
    part1.getuidL = function() {
            let length = 32;
            let str = 'abcdefghijklmnopqrstuvwxyz0123456789'
            var id = []
            for (var i = 0; i < length; i++) {
                id[i] = str.charAt(Math.random() * 36)
            }
            return id.join('')
        }
        //深拷贝
    part1.deepCopy = function(item) {
        var newarr = Array.isArray(item) ? [] : {}
        for (var key in item) {
            if (item.hasOwnProperty(key)) {
                if (typeof item[key] === 'object' && item[key] !== null) {
                    newarr[key] = this.deepCopy(item[key])
                } else {
                    newarr[key] = item[key]
                }
            }
        }
        return newarr
    }

    /**
     * //key值转换
     * 没啥用了 用下面的 changeKeysInFormData ,当要处理的对象数组中 对象的前俩字段是所需的字段才有作用!!!
     * @param {*} arr
     * @param {*} key
     * @returns
     */
    part1.convertKey = function(arr, key) {
            let newArr = [];
            arr.forEach((item, index) => {
                let newObj = {};
                for (var i = 0; i < key.length; i++) {
                    newObj[key[i]] = item[Object.keys(item)[i]];
                }
                newArr.push(newObj);
            });
            return newArr;
        }
        /**
         * Check if an element has a class
         * @param {HTMLElement} elm
         * @param {string} cls
         * @returns {boolean}
         */
    part1.hasClass = function(ele, cls) {
            return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
        }
        /**
         * Add class to element
         * @param {HTMLElement} elm
         * @param {string} cls
         */
    part1.addClass = function(ele, cls) {
        if (!this.hasClass(ele, cls)) ele.className += ' ' + cls
    }

    /**
     * Remove class from element
     * @param {HTMLElement} elm
     * @param {string} cls
     */
    part1.removeClass = function(ele, cls) {
            if (this.hasClass(ele, cls)) {
                const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
                ele.className = ele.className.replace(reg, ' ')
            }
        }
        /**
         * @param {string} path
         * @returns {Boolean}
         */
    part1.isExternal_p = function(path) {
        return /^(https?:|mailto:|tel:)/.test(path)
    }
    part1.isArray = function(obj) {
        return Object.prototype.toString.call(obj) == '[object Array]';
    }
    part1.isObject = function(obj) {
            return Object.prototype.toString.call(obj) == '[object Object]';
        }
        /**
         * 简单防抖
         * @param {*} fn 要防抖的函数
         * @param {*} delay 防抖的毫秒数
         * @returns
         */
    part1.debounce = function(fn, delay = 100) {
            let timer = null
            return function() {
                let args = arguments
                if (timer) {
                    clearTimeout(timer)
                }
                timer = setTimeout(() => {
                    fn.apply(this, args)
                }, delay)
            }
        }
        /**
         * 选择图片后 转base64格式
         * @param {*} file
         * @returns
         */
    part1.uploadImgToBase64 = function(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader()
            reader.readAsDataURL(file)
            reader.onload = function() {
                resolve(reader)
            }
            reader.onerror = reject
        })
    }

    /**
     * 第二部分 时间函数   moment.js有个专门的时间函数库
     *
     */
    var now = new Date(); //当前日期
    var pre = new Date(); //上月日期
    pre.setDate(1); //设置为1号
    pre.setMonth(pre.getMonth() - 1);
    var time = {
        now: now, //当前日期
        nowDay: now.getDate(), //当前日
        nowDayOfWeek: now.getDay(), //
        nowMonth: now.getMonth(), //
        nowYear: now.getFullYear(), //
        preYear: pre.getFullYear(), //上个月的年份
        preMonth: pre.getMonth(), //上个月的月份
    }
    var part2 = {
        /**
         * 将数据的长度补齐 eg得到的毫秒数 秒数 月份等数据 都统一一定的长度
         * @param {*} num 
         * @param {*} len
         * wfy.formatDateNum(58,6) ->000058 
         */
        formatDateNum: function(num, len = 2) {
            var addlen = num.toString().length;
            while (addlen < len) {
                num = "0" + num;
                addlen++;
            }
            return num;
        },
        /**
         * 当你看到这个代码 你估计不会知道他的使用场景！我不会写明它是干嘛的，有兴趣你自己去探索吧~
         * 但是 它是打败度娘介绍中千篇一律的方法，经过实际检验有效的！！，
         * @param {*} numb 
         * @returns 
         */
        formatExcelDate: function(numb) {
            const d = numb - 1;
            const t = Math.round((d - Math.floor(d)) * 24 * 60 * 60);
            return this.format('yyyy-MM-dd hh:mm:ss', new Date(1900, 0, d, 0, 0, t));
        },
		timestampToTime: function(timestamp) {
			const date = new Date(timestamp);
			const year = date.getFullYear();
			const month = ('0' + (date.getMonth() + 1)).slice(-2); // 月份从0开始，所以需要+1
			const day = ('0' + date.getDate()).slice(-2);
			const hours = ('0' + date.getHours()).slice(-2);
			const minutes = ('0' + date.getMinutes()).slice(-2);
			const seconds = ('0' + date.getSeconds()).slice(-2);
			return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
		},
        //获取当前时间。并自定义时间 连接格式 / - . 默认 用-
        format: function(fmt, date) {
            fmt = (fmt || '') + '';
            date = new Date(date || new Date());
            var map = {};
            map['M+'] = date.getMonth() + 1;
            map['d+'] = date.getDate();
            map['h+'] = date.getHours();
            map['m+'] = date.getMinutes();
            map['s+'] = date.getSeconds();
            map['q+'] = Math.floor((date.getMonth() + 3) / 3);
            if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
            if (/(W+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, ['日', '一', '二', '三', '四', '五', '六'][date.getDay()]);
            if (/(S+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, date.getMilliseconds() + '');
            for (var key in map)
                if (new RegExp('(' + key + ')').test(fmt))
                    fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? map[key] : ('00' + map[key]).substr(('' + map[key]).length));
            return fmt;
            //wfy.format('yyyy-MM-dd hh:mm:ss',new Date())
        },
        timestyle: function(str, model) { // 有时候，从后台穿过来的 时间没有连接符号。全是一串数字。为了好看。添加连接符。默认为 -
            var str1 = str.slice(0, 4),
                str2 = str.slice(4, 6),
                str3 = str.slice(6, 8);
            return str1 + (model || "-") + str2 + (model || "-") + str3;
        },
        /**
         * 日期 默认拼接 时分秒 开始是00:00:00,截止是23:59:59 默认是开始
         * @param {*} date
         * @param {*} symbol
         */
        dataPicker(date, symbol = true) {
            //值考虑空和 日期
            if (!this.empty(date)) {
                var d = new Date(date).getTime();
                d = new Date(d);
                d.setHours(symbol ? 0 : 23);
                d.setMinutes(symbol ? 0 : 59);
                d.setSeconds(symbol ? 0 : 59);
                return part2.format('yyyy-MM-dd hh:mm:ss', d);
            } else {
                return date;
            }

        },
        formatDate: function(date, symbol) {
            //symbol 链接符号 默认 不写为空 20180831格式~~~
            var myyear = date.getFullYear();
            var mymonth = date.getMonth() + 1;
            var myweekday = date.getDate();
            if (mymonth < 10) {
                mymonth = "0" + mymonth;
            }
            if (myweekday < 10) {
                myweekday = "0" + myweekday;
            }
            if (!symbol) symbol = '';
            return (myyear + symbol + mymonth + symbol + myweekday); //----------
        },
        getAllDay: function(begin, end) {
            //获取两个日期之间所有日期
            //getAll('2017-02-27', '2017-03-02'); //2017-02-27  2017-02-28 2017-03-01 2017-03-02
            var ab = begin.split("-");
            var ae = end.split("-");
            var db = new Date();
            var arr = [];
            db.setUTCFullYear(ab[0], ab[1] - 1, ab[2]);
            var de = new Date();
            de.setUTCFullYear(ae[0], ae[1] - 1, ae[2]);
            var unixDb = db.getTime();
            var unixDe = de.getTime();
            for (var k = unixDb; k <= unixDe;) {
                k = k + 24 * 60 * 60 * 1000;
                arr.push(wfy.formatDate(new Date(parseInt(k))));
            }
            return arr;
        },
        ////获得今年 某月的天数   nowYear用的是now当前的
        getMonthDays: function(myMonth) {
            var monthStartDate = new Date(time.nowYear, myMonth, 1); // 本月的第一天  格式 ：2016 01 01
            var monthEndDate = new Date(time.nowYear, myMonth + 1, 1); //下个月的第一天  相减得到天数的毫秒
            var days = (monthEndDate - monthStartDate) / (1000 * 60 * 60 * 24); //
            return days;
            //console.log(time.getMonthDays(8)) 注意 参数是从0开始的  8标识 第9个月
        },
        //计算 某年某月天数(用来优化上面的方法)
        getSomeMonthDays: function(year, month) {
            return new Date(year, month, 0).getDate(); //0表示下月的第0天，上月的最后一天,月份从0开始记数
        },
        //获取当前 季度的 开始 月份
        getQuarterStartMonth: function() {
            var quarterStartMonth = 0;
            if (time.nowMonth < 3) {
                quarterStartMonth = 0;
            }
            if (2 < time.nowMonth && time.nowMonth < 6) {
                quarterStartMonth = 3;
            }
            if (5 < time.nowMonth && time.nowMonth < 9) {
                quarterStartMonth = 6;
            }
            if (time.nowMonth > 8) {
                quarterStartMonth = 9;
            }
            return quarterStartMonth;
        },
        //获取 本周 开始 日期
        getWeekStartDate: function() {
            //nowDayOfWeek本周第几天
            //nowDay 本月的日期。减去 本周已经过了的天数。得到 本周开始的日期格式。
            //然后 new Date
            var weekStartDate = new Date(time.nowYear, time.nowMonth, time.nowDay - time.nowDayOfWeek);
            //console.error(weekStartDate)  得到：time.js:41 Sun Jan 08 2017 00:00:00 GMT+0800 (中国标准时间)
            return part2.formatDate(weekStartDate, '-');
        },
        //获取本周 结束 的日期
        getWeekEndDate: function() {
            var weekEndDate = new Date(time.nowYear, time.nowMonth, time.nowDay + (6 - time.nowDayOfWeek));
            return part2.formatDate(weekEndDate, '-');
        },
        //获取本月的 开始 日期
        getMonthStartDate: function() {
            var monthStartDate = new Date(time.nowYear, time.nowMonth, 1);
            return part2.formatDate(monthStartDate, '-');
        },
        //本月 结束  时间
        getMonthEndDate: function() {
            var monthEndDate = new Date(time.nowYear, time.nowMonth, part2.getMonthDays(time.nowMonth));
            return part2.formatDate(monthEndDate, '-');
        },
        //上个月的 开始 日期
        getPreMonthStartDate: function() {
            var preMonthStartDate = new Date(time.preYear, time.preMonth, 1);
            return part2.formatDate(preMonthStartDate, '-');
        },
        //上个月的 结束 日期
        getPreMonthEndDate: function() {
            var preMonthEndDate = new Date(time.preYear, time.preMonth, part2.getMonthDays(time.preMonth));
            return part2.formatDate(preMonthEndDate, '-');
        },

        //本季度的 开始日期
        getQuarterStartDate: function() {
            var quarterStartDate = new Date(time.nowYear, part2.getQuarterStartMonth(), 1);
            return part2.formatDate(quarterStartDate, '-');
        },
        //本季度的 结束 日期
        getQuarterEndDate: function() {
            var quarterEndMonth = part2.getQuarterStartMonth() + 2;
            var quarterStartDate = new Date(time.nowYear, quarterEndMonth, part2.getMonthDays(quarterEndMonth));
            return part2.formatDate(quarterStartDate, '-');
        },
        //年的开始 就简单了 由年份 直接拼写吧
        getYearStartDate: function() {
            return time.nowYear + "-01" + "-01";
        },
        getYearEndDate: function() {
            return time.nowYear + "-12" + "-31";
        },
        //获取某个日期num天后的 日期 没加time的为空判断 使用的时候加以验证
        getNextDay: function(time, num) {
            var d = new Date(time).getTime();
            d = d + 1000 * 60 * 60 * 24 * num;
            d = new Date(d);
            return part2.format('yyyy-MM-dd hh:mm:ss', d);
        },
        //获取某个日期num前后的 日期
        getPreDay: function(time, num) {
            var d = new Date(time).getTime();
            d = d - 1000 * 60 * 60 * 24 * num;
            d = new Date(d);
            return part2.formatDate(d, '-');
        },
        // 托管12个月 获取某个日期以后 几个月的日期
        getNumMonday: function(time, month) {
            var time = new Date(time);
            var y = time.getFullYear();
            var m;
            if (time.getMonth() + month + 1 > 12) {
                y = y + 1;
                m = time.getMonth() + month - 11;
            } else {
                m = time.getMonth() + month + 1;
            }
            var d = time.getDate();
            return y + "-" + m + "-" + d;
        }
    };

    /**
     * 第三部分 string array 等 原型属性扩展
     *
     */
    // 日期格式化
    Date.prototype.format = function(fmt) {
        var o = {
            "M+": this.getMonth() + 1, //月份
            "d+": this.getDate(), //日
            "h+": this.getHours(), //小时
            "m+": this.getMinutes(), //分
            "s+": this.getSeconds(), //秒
            "q+": Math.floor((this.getMonth() + 3) / 3), //季度
            "S": this.getMilliseconds() //毫秒
        };
        if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        for (var k in o)
            if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
        return fmt;
    };
    //使用 new Date().format("yyyy-MM-dd")---直接获取当前日期
    //获取 数组中 某个值得索引(5.3补充：这么写仅适应与不带重复值的数组)
    Array.prototype.getindex = function(val) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == val) {
                return i;
            }
        }
        return -1;
    }

    //删除 数组中的 某个 值
    Array.prototype.remove = function(val) {
        var index = this.getindex(val);
        if (index > -1) {
            this.splice(index, 1); //splice是数组自带的函数,会改变 原数组！
        }
    }

    //5.3 升级：上面的remove方法，如果遇到删除的值 存在多个，并不能实现，换个思路：使用 辅助数组，将将删除值之外的值添加到数组中。
    Array.prototype.removeVal = function(val) {
        var tem = new Array();
        for (var i = 0; i < this.length; i++) {
            if ((this[i] != val) && (tem.indexOf(this[i]) == -1)) {
                tem.push(this[i])
            }
        }
        return tem; //需要对原数组 重新 赋值！！！！！！！！！！
    }

    //判断某个值是否在数组中  （索引的）
    Array.prototype.val_in_array = function(val) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == val)
                return true;
        }
        return false;
    }

    // 判断 某个键 是否 存在 （）
    Array.prototype.key_in_array = function(k) {
            var arr = [];
            for (var key in this) {
                //取得 所有的 key值 组成一个新的 数组；
                arr.push(key);
            }
            if (arr.val_in_array(k)) {
                return true;
            } else {
                return false;
            }
        }
        //判断数组 是否属数组的一部分
    Array.prototype.arr_in_array = function(array) {
        let booleans = true;
        for (let index = 0; index < array.length; index++) {
            const element = array[index];
            if (!this.val_in_array(element)) {
                booleans = false;
            }
        }
        return booleans;
    }

    //判断某个值在数组中的位置
    Array.prototype.indexOf = function(e) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == e)
                return i;
        }
        return -1;
    }

    //判断了两个数组共同拥有的值。并删除
    Array.prototype.del_common = function(arr) {
        for (var i = 0; i < arr.length; i++) {
            if (this.val_in_array(arr[i])) {
                this.remove(arr[i]);
                arr.remove(arr[i]);
            }
        }
    }

    //比较两个数组是否相等
    Array.prototype.equals = function(array) {
        if (!array)
            return false;
        if (this.length != array.length)
            return false;
        for (var i = 0, l = this.length; i < l; i++) {
            if (this[i] instanceof Array && array[i] instanceof Array) {
                if (!this[i].equals(array[i]))
                    return false;
            } else if (this[i] != array[i]) {
                return false;
            }
        }
        return true;
    }
    Array.prototype.max = function() {
            var max = this[0];
            var len = this.length;
            for (var i = 1; i < len; i++) {
                if (this[i] > max) {
                    max = this[i];
                }
            }
            return max;
        }
        /**
         * 以上Array 的扩展方式 用处不多了~ 重点下面~
         * @returns
         */
        //统计一个数组中 每个元素重复的次数  返回对象格式 {元素：次数}
        /**
         * eg arr = [1,1,2,3,5,5]
         *返回 {1:2,2:1,3:1,5:2}
         */
    Array.prototype.getRepeatNum = function() {
            var obj = {};
            for (var i = 0, l = this.length; i < l; i++) {
                var item = this[i];
                obj[item] = (obj[item] + 1) || 1;
            }
            return obj;
        }
        /**
         * 辅助函数 将返回的下拉内容处理成 以tagCode tagValue 为键的格式
         * @param {*} oldKeys
         * @param {*} newKeys
         * @returns
         * newKeys oldKeys 长度保持一致
         * 避坑提示： 下拉组件绑定的是 tagValue 和 tagName
         * 2021/4/21 补充提示 添加第三个参数 特例：当要求下拉内容同时显示 'tagValue', 'tagName'de 时候
         */
    Array.prototype.changeKeysInFormData = function(oldKeys, newKeys = ['tagValue', 'tagName'], showVal = false) {
            let newArr = [];
            this.forEach((item, index) => {
                let newObj = {};
                for (var i = 0; i < newKeys.length; i++) {
                    newObj[newKeys[i]] = item[oldKeys[i]];
                    if (showVal && newKeys[i] == 'tagName') {
                        newObj['tagName'] = newObj['tagValue'] + '  ' + newObj['tagName'];
                    }
                }
                newArr.push(newObj);
            });
            return newArr;
        }
        /**
         * 辅助函数 从 formData 中根据某个键 查 值
         * 参见 formData 的数据结构 根据 tagCode的值 求 tagValue，
         * 一般将值 负载在 tagValue上，当负载在其他字段的时候  需要第二个参数 other
         */
    Array.prototype.getValFromFormData = function(tagCode_val, other) {
            let val = '';
            this.map(item => {
                if (item.tagCode == tagCode_val) {
                    if (other) {
                        val = item[other]
                    } else {
                        val = item['tagValue']
                    }
                }
            })
            return val;
        }
        /**
         * 反向给 formData 赋值！
         * @param {*} tagCode
         * @param {*} tagValue
         */
    Array.prototype.setValToFormData = function(tagCode, tagValue) {
        this.map(item => {
            if (item.tagCode == tagCode) {
                item.tagValue = tagValue;
            }
        })
    }
    Array.prototype.setSelectToFormData = function(tagCode, selectValue) {
            this.map(item => {
                if (item.tagCode == tagCode) {
                    item.selectArr = selectValue;
                }
            })
        }
        /**
         * 辅助函数 从 formData 中根据某个键 查 对象
         * 用于对 该字段对象的其他操作
         */
    Array.prototype.getObjFromFormData = function(tagCode_val) {
            let val;
            this.map(item => {
                if (item.tagCode == tagCode_val) {
                    val = item;
                }
            })
            return val;
        }
        /**
         * 辅助函数 formData 从多个字段值中  依据 tagCode 选择几个组成所需要的 formData
         * 参数 ['name','age']..
         * 情景模拟 几个通用的页面 但是 字段却有点差别 那么可以将所有的字段 和一起 ！
         */
    Array.prototype.getDataFromFormData = function(arr) {
            return this.filter(item => {
                return arr.includes(item.tagCode);
            })
        }
        /**
         * 对象数组 数据的重复性判断
         * @param {*} key 某条数据的键
         * @param {*} val 某条数据的值
         * @returns
         */
    Array.prototype.isIncludeInFormData = function(key, val) {
        let boolean = false;
        for (let index = 0; index < this.length; index++) {
            const element = this[index];
            if (element.hasOwnProperty(key) && element[key] === val) {
                boolean = true;
                break;
            }
        }
        return boolean;
    }

    /**
     * 二维数据，转适用于Vxe-Grid（Tree）的数据
     * @param 转换配置
     * @return TreeData
     */
    Array.prototype.toTreeData = function(config) {
        const _conf = Object.assign({
            idField: 'id',
            pidField: 'pid',
            startWith: null,
            sort: null,
            order: null
        }, config)


        return getSub(null, this, _conf)

        function getSub(parent, arr, conf) {
            let nodeArr = arr.filter(unit => {
                if (conf.startWith) {
                    return parent != unit && unit[conf.pidField] === conf.startWith
                } else {
                    return parent != unit && unit[conf.pidField] === null
                }
            })

            if ('sort' in conf && conf.sort) {
                let order = 1
                if (('order' in conf) && conf.order === 'desc') {
                    order = -1
                }
                nodeArr = nodeArr.sort((v1, v2) => (v1[conf.sort] >= v2[conf.sort] ? (order * 1) : (order * -1)))
            }

            if (nodeArr && nodeArr.length > 0) {
                nodeArr.forEach(node => {
                    conf.startWith = node[conf.idField]
                    const subNodeArr = getSub(node, arr, conf)
                    if (subNodeArr && subNodeArr.length > 0) {
                        node.children = subNodeArr
                    }
                })
                return nodeArr
            } else {
                return []
            }
        }
    }

    Array.prototype.update = function(prop, value) {
        if (XEUtils.isString(prop)) {
            this.forEach(item => {
                item[prop] = value
            })
        } else if (XEUtils.isObject(prop)) {
            this.forEach(item => {
                Object.keys(prop).forEach(k => {
                    item[k] = prop[k]
                })
            })
        }
    }

    //字符串超出省略   len 取双倍！比如要截取三个字 那么设置len参数为6
    String.prototype.cutstr = function(len) {
        var restr = this;
        var wlength = this.replace(/[^\x00-\xff]/g, "**").length;
        if (wlength > len) {
            for (var k = len / 2; k < this.length; k++) {
                if (this.substr(0, k).replace(/[^\x00-\xff]/g, "**").length >= len) {
                    restr = this.substr(0, k) + "...";
                    break;
                }
            }
        }
        return restr;
    }

    //替换全部
    String.prototype.replaceAll = function(s1, s2) {
        return this.replace(new RegExp(s1, "gm"), s2)
    }

    //字符串去空格
    String.prototype.trim = function() {
        return this.replace(/(^\s*)|(\s*$)/g, "");
    }
    String.prototype.trimAll = function() {
        return this.replace(/\s+/g, "");
    }
    String.prototype.lTrim = function() {
        return this.replace(/(^\s*)/g, "");
    }
    String.prototype.rTrim = function() {
            return this.replace(/(\s*$)/g, "");
        }
        //换行
    String.prototype.rEnter = function() {
        return this.replace(/[\r\n]/g, "")
    }

    //判断是否以某个字符串开头
    String.prototype.startWith = function(s) {
        return this.indexOf(s) == 0
    }

    //判断是否以某个字符串结束
    String.prototype.endWith = function(s) {
        var d = this.length - s.length;
        return (d >= 0 && this.lastIndexOf(s) == d)
    }

    //日期 yyyy-MM-dd 转换为date对象  例如（2019-02-25）
    String.prototype.stringToDate = function() {
        var strDate = this.split(" ");
        var strDatepart = strDate[0].split("-");
        var dtDate = new Date(strDatepart[0], strDatepart[1] - 1, strDatepart[2]);
        return dtDate;
    }

    function extend() {
        var length = arguments.length;
        var target = arguments[0] || {};
        if (typeof target != "object" && typeof target != "function") {
            target = {};
        }
        if (length == 1) {
            target = this;
            i--;
        }
        for (var i = 1; i < length; i++) {
            var source = arguments[i];
            for (var key in source) {
                if (Object.prototype.hasOwnProperty.call(source, key)) {
                    target[key] = source[key];
                }
            }
        }
        return target;
    }
    Vue.prototype.wfy = Object.assign({}, part1, part2);
})()